import 'dart:convert';
import 'dart:io';

import 'package:sl_doclever/src/doclever/sl_doc_config.dart';
import 'package:sl_doclever/src/doclever/sl_doc_data.dart';
import 'package:sl_doclever/src/doclever/sl_node.dart';

class SLDoclever {
  List<SLDocData> docDatas;

  final List<String> pathes;

  SLDoclever(this.pathes) {
    var docDataList = <SLDocData>[];

    for (var path in pathes) {
      docDataList.addAll(mapToEntities(stringToMap(path)));
    }

    docDatas = docDataList;
  }

  Map stringToMap(String path) {
    var retMap = {};

    var docStr = File(path).readAsStringSync();

    if (docStr == null || docStr.isEmpty) return retMap;

    retMap = json.decode(docStr);

    return retMap;
  }

  List<SLDocData> mapToEntities(Map dataSource) {
    var retDocData = <SLDocData>[];
    if (dataSource == null || dataSource.isEmpty) return retDocData;

    if (dataSource.keys.contains('data')) {
      List dataList = dataSource['data'];
      for (var data in dataList) {
        retDocData.add(mapToEntity(data));
      }
    } else {
      retDocData.add(mapToEntity(dataSource));
    }

    return retDocData;
  }

  SLDocData mapToEntity(Map data) {
    Map doc = (data['param'] as List).first;

    var rawJSON = [];

    if (doc.keys.contains('bodyInfo')) {
      var bodyInfo = doc['bodyInfo'];
      if (bodyInfo.keys.contains('rawJSON')) {
        rawJSON = bodyInfo['rawJSON'];
      }
    }

    var docData = SLDocData(
      name: data['name'],
      url: data['url'],
      remark: data['remark'],
      method: (data['method'] as String).toUpperCase(),
      header: getALlParams(
        doc['header'],
        isRoot: true,
        fatherNode: SLDocConfig().root,
      ),
      queryParam: getALlParams(
        doc['queryParam'],
        isRoot: true,
        fatherNode: SLDocConfig().root,
      ),
      outParam: getALlParams(
        doc['outParam'],
        isRoot: true,
        fatherNode: SLDocConfig().root,
      ),
      rawJSON: getALlParams(
        rawJSON,
        isRoot: true,
        fatherNode: SLDocConfig().root,
      ),
      headerJson: getALlParamsMap(doc['header']),
      queryParamJson: getALlParamsMap(doc['queryParam']),
      outParamJson: getALlParamsMap(doc['outParam']),
      rawJSONJson: getALlParamsMap(doc['rawJSON']),
    );

    return docData;
  }

  /// 生成双层节点
  /// 对下面的节点进行转换：
  /// [{name: code, type: 0, remark: , must: 1, mock: }, {name: message, type: 0, remark: , must: 1, mock: }, {name: data, type: 4, remark: , must: 1, mock: , data: [{name: resultList, type: 3, remark: , must: 1, mock: , data: [{name: null, type: 4, remark: , must: 1, mock: , data: [{name: communityId, type: 0, remark: 小区ID, must: 1, mock: }, {name: communityName, type: 0, remark: 小区名称, must: 1, mock: }, {name: cityName, type: 0, remark: 城市名称, must: 1, mock: }]}]}]}]
  /// ```
  /// faterNode:_ROOT_,name:code,type:SLNodeType.String,remark:code,value:,isRoot:true
  /// faterNode:_ROOT_,name:message,type:SLNodeType.String,remark:message,value:,isRoot:true
  /// faterNode:_ROOT_,name:data,type:SLNodeType.Object,remark:data,value:,isRoot:true
  /// faterNode:data,name:resultList,type:SLNodeType.Array,remark:resultList,value:,isRoot:false
  /// faterNode:resultList,name:communityId,type:SLNodeType.String,remark:小区ID,value:,isRoot:false
  /// faterNode:resultList,name:communityName,type:SLNodeType.String,remark:小区名称,value:,isRoot:false
  /// faterNode:resultList,name:cityName,type:SLNodeType.String,remark:城市名称,value:,isRoot:false
  /// ```
  List<SLNode> getALlParams(
    List nodes, {
    String fatherNode,
    bool isRoot = false,
  }) {
    var retNode = <SLNode>[];

    try {
      for (Map node in nodes) {
        String name = node['name'];

        String remark = node['remark'];

        int type =
            node.keys.contains('type') ? node['type'] : SLNodeType.String.index;

        String value = node.keys.contains('value') ? node['value'] : '';

        remark = (remark != null && remark.isNotEmpty)
            ? remark
            : name == null || name.isEmpty
                ? 'Object'
                : name;

        var fatherNode_ =
            fatherNode == null || fatherNode.isEmpty ? NODE_NULL : fatherNode;

        retNode.add(SLNode(
          faterNode: fatherNode_,
          name: name,
          type: SLNodeType.values.elementAt(type),
          remark: remark,
          isRoot: isRoot,
          value: value,
        ));

        List data = node['data'];
        if (data != null && data.isNotEmpty) {
          if (type == SLNodeType.Array.index) {
            var first = (data.first != null && data.first.isNotEmpty)
                ? data.first['data']
                : [];

            retNode.addAll(getALlParams(
              first,
              fatherNode: name,
            ));
          } else {
            retNode.addAll(getALlParams(data, fatherNode: name));
          }
        }
      }
    } catch (e, s) {
      print('$e,$s');
    }

    return retNode;
  }

  Map getALlParamsMap(List nodes) {
    var retNode = {};

    try {
      if (nodes == null || nodes.isEmpty) return retNode;

      for (Map node in nodes) {
        String name = node['name'];
        int type =
            node.keys.contains('type') ? node['type'] : SLNodeType.String.index;

        List data = node['data'];

        if (type == SLNodeType.Object.index) {
          retNode[name] = getALlParamsMap(data);
        } else if (type == SLNodeType.Array.index) {
          var first = (data.first != null && data.first.isNotEmpty)
              ? data.first['data']
              : [];
          retNode[name] = [getALlParamsMap(first)];
        } else {
          retNode[name] = '';
        }
      }
    } catch (e, s) {
      print('$e,$s');
    }

    return retNode;
  }
}
